(function(){
    var WORD_BEFORE_REG = /([\s\("])/g,
        WORD_AFTER_REG  = /([\s\.\?\!\)\:,;"])/g,
		KEYWORDS_SEPARATOR = /[\s]*[,]+[\s]*/,
        WORDS_SEPARATOR = /[\s\.\?\!\)\:;\"]+/,
		HIGHLIGHTS_SEPARATOR_REG = /[\s\("\.\?\!\)\:,;\"]+/g;

    String.prototype.insert = function (index, string) {
        if (index > 0) {
            return this.substring(0, index) + string + this.substring(index, this.length);
        } else {
            return string + this;
        }
    };

    function addTerm(matches, term, termMatch, offset){
        var added= false,
            overlap = false,
            item,
            i = 0, l = matches.length;
        // console.debug('addTerm', termMatch, offset, matches.length, matches);

        while(i < l && !overlap){
            if(offset >= matches[i].start && offset <= matches[i].end){
                // console.debug('overlap', offset, termMatch, i, matches[i], term);
                overlap = true;
            }
            i++;
        }
        item = {
            start: offset,
            end: offset + termMatch.length,
            text: termMatch,
            term: term
        };
        if(overlap){
            // don't allow overlap if preview term was not a word
			if(term.words == 0 && matches[i-1].term.words != 0){
                //console.debug('add match %d childs', i);
                matches[i-1].childs = matches[i-1].childs || [];
                matches[i-1].childs.push(item);
                added = true;
            }
        } else {
            matches.push(item);
            added = true;
        }
        return added;
    }

    Ext.util.Terminology = {
        FORMAT_END    : '</span>',
		
		getHighlightsSeparator: function(){
			return HIGHLIGHTS_SEPARATOR_REG;
		},
		
		createHighlightsTerms: function(text, minChars, split){
			var j,
				highlights = [],
				terms = [],
				segments = split ? text.split(HIGHLIGHTS_SEPARATOR_REG) : [text];
			segments.sort(function (a, b) {
                return b.length - a.length;
            });
			for(j=0; j<segments.length; j++) {
				if(segments[j].length < minChars){
					continue;
				}
				// TODO decuple make it based on language
				highlights.push(Bible.escapeDiacriticsRe(Ext.escapeRe(segments[j])));
			}
			if(highlights.length){
				terms.push({
					replaceReg: new RegExp(highlights.join('|'), 'gi'),
					words: 0,
					format: '<span class="termshighlight">'
				});
			}
			console.debug('created highlight terms', terms);
			
			return {
				segments: segments,
				terms: terms
			};
		},
		
		createTerms: function(store){
            var terms = [];
            store.each(function(r){
                var k = r.get('keywords'),
                    id = r.get('id'),
					wordsCount,
                    keys = {},
                    format = Bible.util.Format.keywordSpan(r.get('style'), r.get('cls'));
                k = k.split(KEYWORDS_SEPARATOR);

                Ext.each(k, function(e){
                    if(e != ''){
                        wordsCount = e.split(WORDS_SEPARATOR).length;
                        e = Ext.escapeRe(e);
                        if(!keys[wordsCount]){// create array if doesn't exist
                            keys[wordsCount] = [];
                        }
                        keys[wordsCount].push(e);
                    }
                });

                Ext.iterate(keys, function(wordsCount, words){
					words.sort(function (a, b) {
						return b.length - a.length;
					});
                    terms.push({
                        id: id,
                        replaceReg: new RegExp(words.join('|'), 'g'),
                        words: wordsCount,
                        format: format
                    });
                });
            });

            // sort terms based on number of words that they contains
            terms.sort(function (a, b) {
                return b.words - a.words;
            });
			return terms;
        },

        getMatches: function(text, terms){
            var matches = [],
                term,
                len = text.length;

            function termsHighlight(fullMatch, offset, original){
                var endOffset = offset + fullMatch.length;
                //console.debug('termsHighlight', arguments, endOffset);
                if (((offset == 0 || original[offset - 1].match(WORD_BEFORE_REG)) &&
                    (endOffset == len || original[endOffset].match(WORD_AFTER_REG))) || term.words == 0) {
                    addTerm(matches, term, fullMatch, offset);
                }
				//_logger_block_start
				else {
					//console.debug("don't add term", term, fullMatch, offset, endOffset);
					//console.debug('after letter', offset>0 ? original[offset - 1]:'',':', original[endOffset]);
				}
				//_logger_block_end

                return fullMatch;
            }

            Ext.each(terms, function(e){
                term = e;
                text.replace(e.replaceReg, termsHighlight);
            });

            matches.sort(function (a, b) {
                return b.start - a.start;
            });
            //console.debug('matches', matches);
            return matches;
        },

        markup: function(text, matches){
            //console.debug('matches', matches);
            Ext.each(matches, function(e, i){
                //console.debug('markup', e);
                text = text.insert(e.end, Ext.util.Terminology.FORMAT_END);
                if(e.childs){
                    var subTerm = e.childs[0];
                    //console.debug('childs terms', e.childs);
                    text = text.insert(subTerm.end, Ext.util.Terminology.FORMAT_END);
                    text = text.insert(subTerm.start, subTerm.term.format);
                }
                text = text.insert(e.start, e.term.format);
            });
            return text;
        },

        highlight: function(text, terms){
            var matches = Ext.util.Terminology.getMatches(text, terms),
                newText = Ext.util.Terminology.markup(text, matches);
            return {
                text: newText,
                matches: matches
            };
        }
    };

    // test
// var terms = Bible.data.KeywordsStore.keywordsReplace;
// var text = "credinţa în Hristos Isus.";
// console.dir(Ext.util.Terminology.highlight(text, terms));

})();
